/*
 * Block.cpp
 *
 *  Created on: Sep 19, 2011
 *      Author: Belen
 */
#include "Block.h"

unsigned long Block::getId() {
	return id;
}

void Block::setId(unsigned long xId) {
	id = xId;
}

unsigned long Block::getFreeSpace() {
	return freeSpace;
}

unsigned long Block::getRecordCount() {
	return recordCount;
}

char Block::getDirty() {
	return dirty;
}

char* Block::getRawBlock() {
	return rawBlock;
}

void Block::setFreeSpace(unsigned long _free) {
	freeSpace = _free;
	char* ptr = reinterpret_cast<char*>(&freeSpace);
	for (unsigned int i = 0; i < sizeof(unsigned long); i++, ptr++) {
		*(rawBlock + i) = *ptr;
	}
}

void Block::setRecordCount(unsigned long _count) {
	recordCount = _count;
	char* ptr = reinterpret_cast<char*>(&recordCount);
	for (unsigned int i = 0; i < sizeof(unsigned long); i++, ptr++) {
		*(rawBlock + sizeof(unsigned long) + i) = *ptr;
	}
}

bool Block::getRecord(unsigned long id, char** record,
		unsigned long* recordSize) {
	if (id > recordCount || id < 0)
		return false;

	if (*record != NULL
		)
		return false;

	unsigned long pos = 2 * sizeof(unsigned long);
	unsigned long _recCount = recordCount;
	unsigned long _id = 0;

	bool found = false;

	for (unsigned long j = pos; j < blockSize && _recCount > 0;
			_recCount--, _id++) {
		unsigned long regSize = -1;

		char* ptr = reinterpret_cast<char*>(&regSize);
		for (unsigned int i = 0; i < sizeof(unsigned long); i++) {
			*ptr = *(rawBlock + i + j);
			ptr++;
		}

		if (regSize != -1) {
			// valid reg.
			if (id == _id) {
				// found
				(*record) = new char[regSize];
				(*recordSize) = regSize;
				if (*record != NULL) {
					//TODO pasar con memcpy
					for (unsigned long k = 0; k < regSize; k++) {
						(*record)[k] = *(rawBlock + j + sizeof(unsigned long)
								+ k);
					}
					found = true;
				}
				break;
			}
		}

		if (regSize != -1) {
			pos += regSize + sizeof(unsigned long);
			j = pos;
		}
	}

	return found;
}

bool Block::deleteRecord(unsigned long id) {
	if (id > recordCount || id < 0) {
		return false;
	}

	unsigned long pos = 2 * sizeof(unsigned long);


	unsigned long _recCount = recordCount;
	unsigned long _id = 0;

	bool removed = false;

	// aqui se guarda el registro ordenado
	char * aux = new char[blockSize];
	unsigned long pos2 = pos;

	unsigned long spaceRemoved = 0;

	for (unsigned long j = pos; j < blockSize && _recCount > 0;
			_recCount--, _id++) {
		unsigned long regSize = -1;

		char* ptr = reinterpret_cast<char*>(&regSize);
		for (unsigned int i = 0; i < sizeof(unsigned long); i++) {
			*ptr = *(rawBlock + i + j);
			ptr++;
		}

		if (regSize != -1) {
			// valid reg.
			if (id != _id) {
				// no es el registro a borrar

				//copio cabecera de tamaño
				ptr = reinterpret_cast<char*>(&regSize);
				for (unsigned int i = 0; i < sizeof(unsigned long); i++) {
					aux[pos2] = *ptr;
					ptr++;
					pos2++;
				}

				// copio info
				for (unsigned long k = 0; k < regSize; k++) {
					aux[pos2] = *(rawBlock + j + sizeof(unsigned long) + k);
					pos2++;
				}
			}
			else {
				removed = true;
				spaceRemoved = regSize + sizeof(unsigned long);
			}
		}

		if (regSize != -1) {
			pos += regSize + sizeof(unsigned long);
			j = pos;
		}
	}

	if (removed == true) {
		delete rawBlock;
		rawBlock = aux;
		setRecordCount(recordCount-1);
		setFreeSpace(freeSpace + spaceRemoved);
	}


	return true;
}

bool Block::addRecord(char* record, unsigned long recordSize) {
	if (freeSpace < sizeof(unsigned long) + recordSize)
		return false;

	unsigned long pos = 2 * sizeof(unsigned long);
	unsigned long _recCount = recordCount;
	for (unsigned long j = pos; j < blockSize && _recCount > 0;
			 _recCount--) {
		unsigned long regSize = -1;

		char* ptr = reinterpret_cast<char*>(&regSize);
		for (unsigned int i = 0; i < sizeof(unsigned long); i++) {
			*ptr = *(rawBlock + i + j);
			ptr++;
		}

		if (regSize != -1) {
			pos += regSize + sizeof(unsigned long);
			j = pos;
		}
	}

	// guardo tamaño del record
	char* ptr = reinterpret_cast<char*>(&recordSize);
	for (unsigned int i = 0; i < sizeof(unsigned long); i++, ptr++) {
		*(rawBlock + pos + i) = *ptr;
	}
	pos += sizeof(unsigned long);
	for (unsigned long i = 0; i < recordSize; i++, pos++) {
		rawBlock[pos] = record[i];
	}

	setRecordCount(recordCount + 1);
	setFreeSpace(freeSpace - sizeof(unsigned long) - recordSize);
	return true;
}

void Block::emptyBlock() {

	setRecordCount(0);
	setFreeSpace(blockSize-2*sizeof(unsigned long));

}

Block::Block(unsigned long _blockSize) {
	blockSize = _blockSize;
	rawBlock = new char[blockSize];

	// espacio libre y cant. de registros
	setRecordCount(0);
	setFreeSpace(blockSize - 2 * sizeof(unsigned long));
}

Block::Block(char* serializedData, unsigned long _blockSize) {
	blockSize = _blockSize;
	rawBlock = new char[blockSize];

	memcpy(rawBlock, serializedData, blockSize);

	char* ptr;
	// leo freespace
	ptr = reinterpret_cast<char*>(&freeSpace);
	for (unsigned int i = 0; i < sizeof(unsigned long); i++) {
		*ptr = *(rawBlock + i);
		ptr++;
	}

	// leo recordcount
	ptr = reinterpret_cast<char*>(&recordCount);
	for (unsigned int i = 0; i < sizeof(unsigned long); i++) {
		*ptr = *(rawBlock + sizeof(unsigned long) + i);
		ptr++;
	}
}

Block::~Block() {
	delete rawBlock;
}

